﻿@using Maestro.MapPublisher.Common
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@Model.Title</title>
    <link rel="stylesheet" href="assets/css/fontello.css" />
    <link rel="stylesheet" href="assets/ol.css" />
    <link rel="stylesheet" href="assets/ol-ext.min.css" />
    <style type="text/css">
        html,
        body {
            padding: 0;
            margin: 0;
            font-family: Verdana, Geneva, Tahoma, sans-serif;
        }

        html,
        body,
        #map {
            width: 100%;
            height: 100%;
        }

        .ol-mouse-position {
            position: absolute;
            bottom: auto;
            left: auto;
            right: 5px;
            top: 5px;
            background-color: rgba(0, 60, 136, 0.5);
            color: white;
            font-size: 8pt;
        }

        @if (!string.IsNullOrEmpty(Model.UTFGridUrl))
        {<text>
        #feature-info {
            font-family: Verdana, sans-serif;
            border-radius: 3px;
            padding: 4px;
            font-size: 0.8em;
            background-color: white;
        }
        </text>
        }

        .ol-popup {
            position: absolute;
            background-color: white;
            -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
            filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
            padding: 15px;
            border-radius: 10px;
            border: 1px solid #cccccc;
            bottom: 12px;
            left: -50px;
            min-width: 280px;
        }
        .ol-popup:after, .ol-popup:before {
            top: 100%;
            border: solid transparent;
            content: " ";
            height: 0;
            width: 0;
            position: absolute;
            pointer-events: none;
        }
        .ol-popup:after {
            border-top-color: white;
            border-width: 10px;
            left: 48px;
            margin-left: -10px;
        }
        .ol-popup:before {
            border-top-color: #cccccc;
            border-width: 11px;
            left: 48px;
            margin-left: -11px;
        }
        .ol-popup-closer {
            text-decoration: none;
            position: absolute;
            top: 2px;
            right: 8px;
        }
        .ol-popup-closer:after {
            content: "✖";
        }
        .enable-tile-tooltips {
            left: 8px;
            top: 290px;
        }
        .enable-tile-tooltips.ol-active {
            background-color: #ff9900;
        }
    </style>
</head>

<body>
    <div id="map">

    </div>
    @if (!string.IsNullOrEmpty(Model.UTFGridUrl))
    {
        <div style="display: none;">
            <!-- Overlay with the feature info -->
            <div id="feature-info">
                <div id="feature-name">&nbsp;</div>
            </div>
        </div>
    }
    <div style="display: none;">
        <div id="popup" class="ol-popup">
            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
            <div id="popup-content"></div>
        </div>
    </div>
    <script type="text/javascript" src="assets/ol.js" charset="utf-8"></script>
    <script type="text/javascript" src="assets/ol-ext.min.js" charset="utf-8"></script>
    <script type="text/javascript" src="assets/ol-style-support.js" charset="utf-8"></script>
    @if (Model.HasOverlayLayer(OverlayLayerType.GeoJSON_FromMapGuide))
    {
    <script type="text/javascript" src="assets/geojson-vt.js" charset="utf-8"></script>
    }
    @if (Model.OverlayLayers != null)
    {
        foreach (var extLayer in Model.OverlayLayers)
        {
            if (extLayer.Type == OverlayLayerType.GeoJSON_FromMapGuide)
            {
    <script type="text/javascript" src="@(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.DataScriptRelPath)" charset="utf-8"></script>
    <script type="text/javascript" src="@(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.ConfigScriptRelPath)" charset="utf-8"></script>
            }
        }
    }
    <script type="text/javascript">

        var mapBounds = [ @Model.LatLngBounds[0], @Model.LatLngBounds[1], @Model.LatLngBounds[2], @Model.LatLngBounds[3] ];
        var viewBounds = ol.proj.transformExtent(mapBounds, 'EPSG:4326', 'EPSG:3857');

        @if (!string.IsNullOrEmpty(Model.UTFGridUrl))
        {<text>
        var gUTFGridTipsEnabled = true;
        var utfGridSource = new ol.source.UTFGrid({
            tileJSON: {
            scheme: "xyz",
                grids: [
                    "@Raw(Model.UTFGridUrl)"
                ]
            }
        });
        var utfGridLayer = new ol.layer.Tile({
            title: "MapGuide XYZ UTFGrid",
            extent: viewBounds,
            source: utfGridSource,
            displayInLayerSwitcher: false //There's no point providing toggle-ability for this layer
        });
        </text>
        }

        var baseLayerList = [];
        @if (Model.ExternalBaseLayers != null)
        {
            int counter = 0;
            foreach (var extLayer in Model.ExternalBaseLayers)
            {
                switch (extLayer.Type)
                {
                    case ExternalBaseLayerType.OSM:
                        <text>
        var @(extLayer.Type)_@(counter) = new ol.source.OSM();
        baseLayerList.push({ name: "@extLayer.Name", visible: @(counter == 0 ? "true" : "false"), source: @(extLayer.Type)_@(counter) });
                        </text>
                        break;
                    case ExternalBaseLayerType.Stamen:
                        <text>
        var @(extLayer.Type)_@(counter) = new ol.source.Stamen({
            layer: "@extLayer.LayerType.ToString().ToLower()"
        });
        baseLayerList.push({ name: "@extLayer.Name", visible: @(counter == 0 ? "true" : "false"), source: @(extLayer.Type)_@(counter) });
                        </text>
                        break;
                    case ExternalBaseLayerType.XYZ:
                        <text>
        var @(extLayer.Type)_@(counter) = new ol.source.XYZ({
            url: "@Raw(extLayer.UrlTemplate)"
        });
        baseLayerList.push({ name: "@extLayer.Name", visible: @(counter == 0 ? "true" : "false"), source: @(extLayer.Type)_@(counter) });
                        </text>
                        break;
                    case ExternalBaseLayerType.BingMaps:
                        <text>
        var @(extLayer.Type)_@(counter) = new ol.source.BingMaps({
            key: "@(((BingMapsBaseLayer)extLayer).ApiKey)",
            imagerySet: "@(((BingMapsBaseLayer)extLayer).LayerType)",
        });
        baseLayerList.push({ name: "@extLayer.Name", visible: @(counter == 0 ? "true" : "false"), source: @(extLayer.Type)_@(counter) });
                        </text>
                        break;
                }
                counter++;
            }
        }

        var mapElement = document.getElementById('map');
        var mapLayers = [];
        var baseGroup = new ol.layer.Group({
            title: "Base Maps",
            openInLayerSwitcher: true,
            layers: baseLayerList.map(function (bl) {
                return new ol.layer.Tile({
                    title: bl.name,
                    baseLayer: true,
                    visible: bl.visible,
                    source: bl.source
                });
            })
        });
        mapLayers.push(baseGroup);
        @if (!string.IsNullOrEmpty(Model.XYZImageUrl))
        {<text>
        mapLayers.push(new ol.layer.Tile({
            title: 'MapGuide XYZ Image',
            type: 'base',
            extent: viewBounds,
            source: new ol.source.XYZ({
                url: "@Raw(Model.XYZImageUrl)"
            })
        }));
        </text>
        }
        @if (!string.IsNullOrEmpty(Model.UTFGridUrl))
        {<text>
        mapLayers.push(utfGridLayer);
        </text>
        }

        var vtTilePixels = new ol.proj.Projection({
            code: 'TILE_PIXELS',
            units: 'tile-pixels'
        });
        var vt_replacer = function(key, value) {
            if (value.geometry) {
              var type;
              var rawType = value.type;
              var geometry = value.geometry;

              if (rawType === 1) {
                type = 'MultiPoint';
                if (geometry.length == 1) {
                  type = 'Point';
                  geometry = geometry[0];
                }
              } else if (rawType === 2) {
                type = 'MultiLineString';
                if (geometry.length == 1) {
                  type = 'LineString';
                  geometry = geometry[0];
                }
              } else if (rawType === 3) {
                type = 'Polygon';
                if (geometry.length > 1) {
                  type = 'MultiPolygon';
                  geometry = [geometry];
                }
              }

              return {
                'type': 'Feature',
                'geometry': {
                  'type': type,
                  'coordinates': geometry
                },
                'properties': value.tags
              };
            } else {
              return value;
            }
        };

        var popupTemplates = {};
        var overlayList = [];
        @if (Model.OverlayLayers != null)
        {
            int counter = 0;
            foreach(var extLayer in Model.OverlayLayers)
            {
                switch (extLayer.Type)
                {
                    case OverlayLayerType.GeoJSON_FromMapGuide:
                        if (((GeoJSONFromMapGuideOverlayLayer)extLayer).Source.LoadAsVectorTiles)
                        {<text>
        var @(extLayer.Type)_@(counter) = new ol.layer.VectorTile({
            title: "@extLayer.Name",
            visible: @(extLayer.InitiallyVisible ? "true" : "false"),
            style: @(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.GlobalVar)_style,
            source: new ol.source.VectorTile({
                format: new ol.format.GeoJSON(),
                url: "data:", // arbitrary url, we don't use it in the tileLoadFunction
                tileLoadFunction: function(tile) {
                    var format = tile.getFormat();
                    var tileCoord = tile.getTileCoord();
                    var tileIndex = @(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.GlobalVar)_vtindex;
                    var data = tileIndex.getTile(tileCoord[0], tileCoord[1], -tileCoord[2] - 1);
                    var features = format.readFeatures(JSON.stringify({
                        type: 'FeatureCollection',
                        features: (data ? data.features : []).map(function (f) {
                            //This isn't geojson, but the attributes are under "tags"
                            f.tags.OL_LAYER_NAME = "@extLayer.Name";
                            return f;
                        })
                    }, vt_replacer));
                    tile.setLoader(function() {
                        tile.setFeatures(features);
                        tile.setProjection(vtTilePixels);
                    });
                }
            })
        });
        popupTemplates["@extLayer.Name"] = @(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.GlobalVar)_popup_template;
        overlayList.push(@(extLayer.Type)_@(counter));
                        </text>
                        }
                        else
                        {<text>
        var @(extLayer.Type)_@(counter) = new ol.layer.Vector({
            title: "@extLayer.Name",
            visible: @(extLayer.InitiallyVisible ? "true" : "false"),
            style: @(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.GlobalVar)_style,
            source: new ol.source.Vector({
                features: (new ol.format.GeoJSON({
                    dataProjection: "EPSG:4326",
                    featureProjection: "EPSG:3857"
                }))
                .readFeatures(@(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.GlobalVar))
                .map(function (f) {
                    f.set("OL_LAYER_NAME", "@extLayer.Name");
                    return f;
                })
            })
        });
        popupTemplates["@extLayer.Name"] = @(((GeoJSONFromMapGuideOverlayLayer)extLayer).Downloaded.GlobalVar)_popup_template;
        overlayList.push(@(extLayer.Type)_@(counter));
                        </text>
                        }
                        break;
                    case OverlayLayerType.WMS:
                        <text>
        var @(extLayer.Type)_@(counter) = new ol.layer.Tile({
            title: "@extLayer.Name",
            visible: @(extLayer.InitiallyVisible ? "true" : "false"),
            source: new ol.source.TileWMS({
                url: "@Raw(((WMSOverlayLayer)extLayer).Service)",
                params: {
                    "LAYERS": "@(((WMSOverlayLayer)extLayer).Layer)"
                }
            })
        });
        overlayList.push(@(extLayer.Type)_@(counter));
                        </text>
                        break;
                    case OverlayLayerType.WFS:
                        <text>
        var @(extLayer.Type)_@(counter) = new ol.layer.Vector({
            title: "@extLayer.Name",
            visible: @(extLayer.InitiallyVisible ? "true" : "false"),
            source: new ol.source.Vector({
                format: new ol.format.GeoJSON(),
                url: function (extent) {
                    return "@(((WFSOverlayLayer)extLayer).Service)?" +
                        'version=1.1.0&request=GetFeature&typename=' +
                        "@(((WFSOverlayLayer)extLayer).FeatureName)" +
                        '&outputFormat=application/json&srsname=EPSG:3857&' +
                        'bbox=' + extent.join(',') + ',EPSG:3857';
                },
                strategy: ol.loadingstrategy.bbox,
            })
        });
        overlayList.push(@(extLayer.Type)_@(counter));
                        </text>
                        break;
                    default:
                        <text>
        console.warn("Overlay layer type (@extLayer.Type) not yet supported");
                        </text>
                        break;
                }
                counter++;
            }
        }
        for (var i = 0; i < overlayList.length; i++) {
            mapLayers.push(overlayList[i]);
        }

        /**
         * Elements that make up the popup.
         */
        var popupContainer = document.getElementById('popup');
        var popupContent = document.getElementById('popup-content');
        var popupCloser = document.getElementById('popup-closer');

        /**
         * Create an overlay to anchor the popup to the map.
         */
        var popupOverlay = new ol.Overlay({
            element: popupContainer,
            autoPan: true,
            autoPanAnimation: {
                duration: 250
            }
        });


        /**
         * Add a click handler to hide the popup.
         * @@return {boolean} Don't follow the href.
         */
        popupCloser.onclick = function() {
            popupOverlay.setPosition(undefined);
            popupCloser.blur();
            return false;
        };

        var defaultMapControls = [];
        defaultMapControls.push(new ol.control.ScaleLine());
        defaultMapControls.push(new ol.control.MousePosition({
            projection: 'EPSG:4326',
            coordinateFormat: function (coordinate) {
                return ol.coordinate.format(coordinate, 'Lat: {y}, Lng: {x}', 4);
            }
        }));
        defaultMapControls.push(new ol.control.ZoomSlider());
        var zeIcon = document.createElement("i");
        zeIcon.className = "icon-resize-full-alt";
        defaultMapControls.push(new ol.control.ZoomToExtent({
            label: zeIcon,
            extent: viewBounds
        }));
        var map = new ol.Map({
            target: mapElement,
            controls: ol.control.defaults({
                attributionOptions: {
                    collapsible: true
                }
            }).extend(defaultMapControls),
            layers: mapLayers
        });
        var mapView = new ol.View({
            projection: 'EPSG:3857',
            extent: viewBounds
        });
        mapView.fit(viewBounds, { size: map.getSize() });
        map.setView(mapView);

        @if (!string.IsNullOrEmpty(Model.UTFGridUrl))
        {<text>
        var infoElement = document.getElementById('feature-info');
        var nameElement = document.getElementById('feature-name');

        var infoOverlay = new ol.Overlay({
            element: infoElement,
            offset: [15, 15],
            stopEvent: false
        });
        map.addOverlay(infoOverlay);
        map.addOverlay(popupOverlay);

        var displayFeatureInfo = function (coordinate) {
            var viewResolution = /** @@type {number} */ (mapView.getResolution());
            utfGridSource.forDataAtCoordinateAndResolution(coordinate, viewResolution,
                function (data) {
                    // If you want to use the template from the TileJSON,
                    //  load the mustache.js library separately and call
                    //
                    mapElement.style.cursor = (data && data.MG_URL) ? 'pointer' : '';
                    if (data) {
                        /*
                        var html = "<table>";
                        for (var key in data) {
                            html += "<tr><td>" + key + "</td><td>" + data[key] + "</td></tr>";
                        }
                        html += "</table>";
                        */
                        var html = "";
                        if (data.MG_TOOLTIP)
                            html += data.MG_TOOLTIP.replace(/(\\n)+/g, '<br />');
                        if (data.MG_URL) {
                            html += "<br/><br/>";
                            html += "<strong>CTRL + Click for more information</strong>";
                        }
                        nameElement.innerHTML = html
                    }
                    infoOverlay.setPosition(data ? coordinate : undefined);
                });
        };
        map.on('pointermove', function (evt) {
            if (evt.dragging || !gUTFGridTipsEnabled) {
                return;
            }
            var coordinate = map.getEventCoordinate(evt.originalEvent);
            displayFeatureInfo(coordinate);
        });
        map.on('click', function (evt) {
            if (!gUTFGridTipsEnabled) {
                return;
            }
            if (evt.originalEvent.ctrlKey == true) {
                var viewResolution = /** @@type {number} */ (view.getResolution());
                gridSource.forDataAtCoordinateAndResolution(evt.coordinate, viewResolution,
                    function (data) {
                        if (data && data.MG_URL) {
                            window.open(data.MG_URL);
                        }
                    });
            }
        });
        function setUTFGridTipsEnabled(bEnabled) {
            gUTFGridTipsEnabled = bEnabled;
            if (!gUTFGridTipsEnabled) {
                nameElement.innerHTML = "";
                popupOverlay.setPosition(undefined);
                popupCloser.blur();
            }
        }

        var utfGridTipToggleCtrl = new ol.control.Toggle({
            html: '<i class="icon-comment"></i>',
            className: "enable-tile-tooltips",
            title: "Toggle tile tooltips",
            active: true,
            onToggle: function(active)
            {
                setUTFGridTipsEnabled(active);
            }
        });
        map.addControl(utfGridTipToggleCtrl);

        </text>
        }

        var ctrl = new ol.control.LayerSwitcher({
            show_progress:true,
            extent: true
        });
        map.addControl(ctrl);

        // Select interaction
        var select = new ol.interaction.Select({
            hitTolerance: 5,
            multi: false,
            condition: ol.events.condition.singleClick
        });
        select.on("select", function (e) {
            if (e.selected.length == 0) {
                popupOverlay.setPosition(undefined);
                popupCloser.blur();
            } else {
                var sf = e.selected[0];
                var layer = sf.get("OL_LAYER_NAME");
                if (popupTemplates[layer]) {
                    popupContent.innerHTML = popupTemplates[layer](sf);
                    var coord = ol.extent.getCenter(sf.getGeometry().getExtent());
                    popupOverlay.setPosition(coord);
                }
            }
        });
        map.addInteraction(select);

    </script>
</body>

</html>